/****
	Copyright 2011 Taras Kulbachka

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

		http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/
package com.atdevsoft.apps.abyss;

import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public abstract class AbstractQuoteDownloader {
    public final static int STATUS_OK = 0;
    public final static int STATUS_SKIP_QUOTE = 1;
    public final static int STATUS_SKIP_PAGE = 2;
    public final static int STATUS_FALLBACK_PAGE = 3;
    public final static int STATUS_ABORT = 4;
	
    public interface OnPageProcessedListener {
        void onPageProcessed(final int page, final int quotesAdded, final int quotesSkipped);
        void onAllPagesProcessed(final int resultCode, final int totalQuotesAdded);
    }	    
	
	public int Status;
	public int PageSavedQuotes;
	public int PageSkippedQuotes;
	public int TotalSavedQuotes;
	public int QuotesSitePageNumber;	
	
	protected SQLiteDatabase mDb;
	protected boolean mTerminateOnDuplicates;
	
	private String mTableName;
	private ContentValues data;	
    private OnPageProcessedListener mProcessedListener;
	


    public AbstractQuoteDownloader(SQLiteDatabase db, String tableName) {
    	mDb = db;
    	mTableName = tableName;
    }    
    
	protected abstract int getNearestSavedQuote(int quoteId);
	protected abstract boolean processTag(TagNode tag, ContentValues output, boolean fastDownload); // returns true if may iterate subnodes
	protected abstract String getPageAddress(int pageNumber);
	
    private void iterateTags(Node node, ContentValues data, boolean fastDownload) throws ParserException {	    	
    	if (node instanceof TagNode) {
            TagNode tag = (TagNode)node;
            boolean subProcess = processTag(tag, data, fastDownload);
            
            if (Status == STATUS_SKIP_QUOTE) {            
            	PageSkippedQuotes++;
            	Status = STATUS_OK;
            } else            
            if ((Status == STATUS_OK) && ((data.size() > 0))) {
            	mDb.insert(mTableName, null, data);
            	PageSavedQuotes++;
                data.clear();
            } 
            if (subProcess)	{
                data.clear();            	
            	if (Status == STATUS_OK) {
            		NodeList nl = tag.getChildren();	            
            		if (nl != null)
            			for (NodeIterator i = nl.elements(); i.hasMoreNodes(); ) {
            				if (Status == STATUS_OK) 
            					iterateTags(i.nextNode(), data, fastDownload);
            				else
            					return;
	                }
            	}
            }
    	}
    }		
    
    public void parsePage(String page, boolean terminateOnDuplicates, boolean fastDownload) {
    	mTerminateOnDuplicates = terminateOnDuplicates;
    	PageSavedQuotes = 0;
    	PageSkippedQuotes = 0;
    	if (data == null)	    		
    		data = new ContentValues();	
    	else
    		data.clear();
    	Status = STATUS_OK;
        mDb.beginTransaction();
        try {
	       	try {
	       		Parser parser = new Parser(page);
				for (NodeIterator i = parser.elements (); i.hasMoreNodes(); )
    				if (Status == STATUS_OK || Status == STATUS_SKIP_QUOTE) 
    					iterateTags(i.nextNode(), data, fastDownload);
    				else
    					return;
			} catch (ParserException e) {
				e.printStackTrace();
			}		
			mDb.setTransactionSuccessful();					
        } finally {
        	mDb.endTransaction();
        }
    }
    
    public void parsePages(int pagesCount, boolean terminateOnDuplicates, boolean fastDownload, boolean reversePageNumbers) {
    	QuotesSitePageNumber = 0;	  
    	TotalSavedQuotes = 0;	    	
    	for (int i = 0; i < pagesCount; i ++) {
    		if (Status != STATUS_ABORT) {
	    		if (QuotesSitePageNumber <= 0) {
	    			parsePage(getPageAddress(QuotesSitePageNumber), terminateOnDuplicates, fastDownload);
	    		} else {
	    			if (!((Status != STATUS_FALLBACK_PAGE) ^ reversePageNumbers))
	    				parsePage(getPageAddress(QuotesSitePageNumber - 1), terminateOnDuplicates, fastDownload);
	    			else
	    				parsePage(getPageAddress(QuotesSitePageNumber + 1), terminateOnDuplicates, fastDownload);
	    		}
				Log.d("abyss", "after page parsed");	    		
                if (mProcessedListener != null) {            		
                	mProcessedListener.onPageProcessed(QuotesSitePageNumber, PageSavedQuotes, PageSkippedQuotes);
                }	    		
    		}
    		TotalSavedQuotes += PageSavedQuotes;
    	}
        if (mProcessedListener != null) {            		
        	mProcessedListener.onAllPagesProcessed(Status, TotalSavedQuotes);
        }	    	
    	
    }
    
    public void setOnPageProcessedListener(OnPageProcessedListener listener) {
    	mProcessedListener = listener;
    }

}
